package com.xh3140.xrouter;

import android.app.Activity;
import android.content.Context;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class RouterManager {
  private static final String PACKAGE_NAME;
  private static final String CLASS_NAME_REGISTER = "RouterRegister";
  private static final Pattern PATTERN_CHECK = Pattern.compile("[_a-zA-Z][-_a-zA-Z0-9]*");
  private static final Pattern PATTERN_REPLACE = Pattern.compile("[-_]+([a-zA-Z])");

  /**
   * The router table.
   * save the path and mapping target activity class.
   */
  private final Map<String, Class<? extends Activity>> table;

  static {
    Package thisPackage = Router.class.getPackage();
    if (thisPackage == null) {
      throw new IllegalStateException("no package!");
    }
    PACKAGE_NAME = thisPackage.getName();
  }

  private RouterManager() {
    table = new HashMap<String, Class<? extends Activity>>();
  }

  /**
   * Use singleton design pattern.
   * Lazy loading.
   */
  private final static class SingletonHolder {
    private static final RouterManager INSTANCE = new RouterManager();
  }

  private static String moduleRegisterName(String moduleName) {
    if (moduleName == null || !PATTERN_CHECK.matcher(moduleName).matches()) {
      throw new IllegalArgumentException("error arg moduleName: " + moduleName);
    }
    Matcher matcher;
    char first = moduleName.charAt(0);
    if (first != '-' && first != '_') {
      matcher = PATTERN_REPLACE.matcher("_" + moduleName);
    } else {
      matcher = PATTERN_REPLACE.matcher(moduleName);
    }
    StringBuffer buffer = new StringBuffer();
    while (matcher.find()) {
      String group = matcher.group(1);
      if (group != null) {
        matcher.appendReplacement(buffer, group.toUpperCase());
      }
    }
    matcher.appendTail(buffer);
    buffer.append(CLASS_NAME_REGISTER);
    return buffer.toString();
  }

  public static void register(String path, Class<? extends Activity> target) {
    if (path == null) {
      throw new IllegalArgumentException("router path is null.");
    }
    if (target == null) {
      throw new IllegalArgumentException("router target activity is null.");
    }
    if (path.isEmpty()) {
      throw new IllegalArgumentException("router path is empty.");
    }
    Class<? extends Activity> old = SingletonHolder.INSTANCE.table.get(path);
    if (old != null) {
      throw new IllegalArgumentException("router path is used: " + path);
    }
    SingletonHolder.INSTANCE.table.put(path, target);
  }

  public static Class<? extends Activity> routing(String path) {
    if (path == null) {
      throw new IllegalArgumentException("router path is null.");
    }
    if (path.isEmpty()) {
      throw new IllegalArgumentException("router path is empty.");
    }
    Class<? extends Activity> target = SingletonHolder.INSTANCE.table.get(path);
    if (target == null) {
      throw new NullPointerException("route target activity is null.");
    }
    return target;
  }

  /**
   * Load the module routing component(Activity).
   *
   * @param context     the Application context.
   * @param moduleNames the Application modules.
   */
  public static void init(Context context, String... moduleNames) {
    if (context == null) {
      throw new IllegalArgumentException("router app context is null.");
    }
    if (moduleNames == null) {
      throw new IllegalArgumentException("router module names is null.");
    }
    if (moduleNames.length < 1) {
      throw new IllegalArgumentException("router module names is empty.");
    }
    ClassLoader classLoader = context.getClassLoader();
    for (String moduleName : moduleNames) {
      String className = PACKAGE_NAME + "." + moduleRegisterName(moduleName);
      try {
        Class<?> cls = Class.forName(className, true, classLoader);
        if (RouterRegister.class.isAssignableFrom(cls)) {
          ((RouterRegister) cls.getDeclaredConstructor().newInstance()).registering();
        }
      } catch (Exception e) {
        throw new IllegalStateException(e);
      }
    }
  }
}